package com.coding.v3;


import com.coding.v3.util.FileUtil;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateExceptionHandler;

import java.io.*;
import java.sql.*;
import java.util.*;


/**
 * @description <功能描述>
 * @author: <user>
 * @Date: 2023/7/26 13:43
 */
public class CodeGenerator {

    private static final String tempFilePath = "src/main/temp/";

    private static final  String templateFilePath = "tlzf/template/";

    private static Configuration cfg;

    static {
        cfg = getFreeMakerCfg();
    }

    public static void main(String[] args) throws Exception {


        InputStream inputStream = CodeGenerator.class.getClassLoader().getResourceAsStream("jdbc.properties");
        Properties ps = new Properties();
        ps.load(inputStream);

        String url = ps.getProperty("url");
        String username = ps.getProperty("username");
        String password = ps.getProperty("password");
        String tableName = ps.getProperty("tableName");
        String driverClass = ps.getProperty("driverClass");

        Class.forName(driverClass);

        try (Connection connection = DriverManager.getConnection(url, username, password)) {
            DatabaseMetaData metaData = connection.getMetaData();
            ResultSet columns = metaData.getColumns(null, null, tableName, null);

            List<TableInfo> columnMappings = new ArrayList<>();
            while (columns.next()) {
                String columnName = columns.getString("COLUMN_NAME");
                String columnType = columns.getString("TYPE_NAME");
                String javaType = sqlTypeToJavaType(columnType);
                String fieldName = toCamelCase(columnName);
                columnMappings.add(new TableInfo(columnName, fieldName, javaType));
            }

            //创建文件夹
            FileUtil.createFolder(tempFilePath);

            // 记录开始时间
            long startTime = System.currentTimeMillis();

            /*1  Execution time: 91 milliseconds */
//            generateEntityClass(tableName, columnMappings);
//            generateEntityXml(tableName, columnMappings);
//            generateMapper(tableName, columnMappings);
//            generateService(tableName, columnMappings);
//            generateServiceImpl(tableName, columnMappings);


            /*2   多线程  Execution time: 90 milliseconds */
            Thread thread1 = new Thread(new Function1(tableName, columnMappings));
            thread1.start();
            Thread thread2 = new Thread(new Function2(tableName, columnMappings));
            thread2.start();


            // 主线程等待所有线程执行完毕
            try {
                thread1.join();
                thread2.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            FileUtil.zipFolder(tempFilePath);
            System.out.println("All threads have finished. Main thread continues.");
            // 记录结束时间
            long endTime = System.currentTimeMillis();
            // 计算执行时间
            long executionTime = endTime - startTime;

            System.out.println("Execution time: " + executionTime + " milliseconds");


        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    /**
     * 将sqlType转为JavaType
     *
     * @param sqlType
     * @return
     */
    private static String sqlTypeToJavaType(String sqlType) {
        // 这里简单示例，你可以根据实际数据库类型进行映射
        switch (sqlType) {
            case "VARCHAR":
            case "CHAR":
                return "String";
            case "INT":
                return "int";
            case "BIGINT":
                return "long";
            case "DECIMAL":
                return "BigDecimal";
            case "DATE":
            case "DATETIME":
                return "String";
            // Add more mappings as needed for your database
            default:
                return "Object";
        }
    }

    /**
     * 将下划线单词转为驼峰
     *
     * @param input
     * @return
     */
    private static String toCamelCase(String input) {
        StringBuilder result = new StringBuilder();
        String[] words = input.toLowerCase().split("_");
        for (int i = 0; i < words.length; i++) {
            String word = words[i];
            result.append(i == 0 ? word : capitalize(word));
        }
        return result.toString();
    }

    private static String capitalize(String input) {
        return input.substring(0, 1).toUpperCase() + input.substring(1);
    }


    /**
     * 将下划线分割的表面转为首字符大写
     *
     * @param input
     * @return
     */
    private static String wordUpperCase(String input) {
        StringBuilder stringBuilder = new StringBuilder();
        String[] s = input.toLowerCase().split("_");
        for (int i = 0; i < s.length; i++) {
            stringBuilder.append(capitalize(s[i]));
        }
        return stringBuilder.toString();
    }

    /**
     * 得到freemaker的配置
     *
     * @return Configuration
     */
    private static Configuration getFreeMakerCfg() {
        Configuration cfg = new Configuration(Configuration.VERSION_2_3_31);
        cfg.setClassForTemplateLoading(CodeGenerator.class, "/");
        cfg.setDefaultEncoding("UTF-8");
        cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
        return cfg;
    }

    /**
     * 得到表的信息
     *
     * @param table          表名
     * @param columnMappings 字段信息
     * @return map
     */
    private static Map<String, Object> getDataModel(String table, List<TableInfo> columnMappings) {
        Map<String, Object> dataModel = new HashMap<>();
        dataModel.put("tableName", table);
        dataModel.put("className", wordUpperCase(table));
        // 去除前缀
        String noPrefixClassName = wordUpperCase(table);
        if (noPrefixClassName.startsWith("T")) {
            noPrefixClassName = noPrefixClassName.substring(1);
        }
        //模块名字
        String moduleName = "com.coding.cz";
        dataModel.put("moduleName", moduleName);
        dataModel.put("noPrefixClassName", noPrefixClassName);
        dataModel.put("columns", columnMappings);
        return dataModel;
    }


    /**
     * 生成Entity原始表信息
     *
     * @param table
     * @param columnMappings
     */
    static void generateEntityClass(String table, List<TableInfo> columnMappings) {
        try {

            Template template = cfg.getTemplate("template/entity_template.ftl");

            Map<String, Object> dataModel = getDataModel(table, columnMappings);
//打印在控制台
//            template.process(dataModel,  new OutputStreamWriter(System.out));

            //输出到文件夹
            Writer out = new FileWriter(new File(tempFilePath + wordUpperCase(table) + ".java"));
            template.process(dataModel, out);

            System.out.println("Entity.java文件生成成功！");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    /**
     * 生成对应的xml文件
     *
     * @param table
     * @param columnMappings
     */
    static void generateEntityXml(String table, List<TableInfo> columnMappings) {
        try {

            Template template = cfg.getTemplate("template/entity_xml_template.ftl");

            Map<String, Object> dataModel = getDataModel(table, columnMappings);

//打印在控制台
//            template.process(dataModel,  new OutputStreamWriter(System.out));

            //输出到文件夹
            Writer out = new FileWriter(new File(tempFilePath + wordUpperCase(table) + ".xml"));
            template.process(dataModel, out);

            System.out.println("Xml文件生成成功！");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    /**
     * 生成对应的service文件
     *
     * @param table
     * @param columnMappings
     */
    static void generateService(String table, List<TableInfo> columnMappings) {
        try {

            Template template = cfg.getTemplate("template/entity_service_template.ftl");

            Map<String, Object> dataModel = getDataModel(table, columnMappings);

//打印在控制台
//            template.process(dataModel,  new OutputStreamWriter(System.out));

            //输出到文件夹
            Writer out = new FileWriter(new File(tempFilePath + dataModel.get("noPrefixClassName") + "Service.java"));
            template.process(dataModel, out);

            System.out.println("Service文件生成成功！");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 生成对应的mapper文件
     *
     * @param table
     * @param columnMappings
     */
    static void generateMapper(String table, List<TableInfo> columnMappings) {
        try {

            Template template = cfg.getTemplate("template/entity_mapper_template.ftl");

            Map<String, Object> dataModel = getDataModel(table, columnMappings);

//打印在控制台
//            template.process(dataModel,  new OutputStreamWriter(System.out));

            //输出到文件夹
            Writer out = new FileWriter(new File(tempFilePath + "I" +dataModel.get("noPrefixClassName") + "Mapper.java"));
            template.process(dataModel, out);

            System.out.println("Mapper文件生成成功！");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    /**
     * 生成对应的ServiceImpl文件
     *
     * @param table
     * @param columnMappings
     */
    static void generateServiceImpl(String table, List<TableInfo> columnMappings) {
        try {

            Template template = cfg.getTemplate("template/entity_serviceImpl_template.ftl");

            Map<String, Object> dataModel = getDataModel(table, columnMappings);

//打印在控制台
//            template.process(dataModel,  new OutputStreamWriter(System.out));

            //输出到文件夹
            Writer out = new FileWriter(new File(tempFilePath + dataModel.get("noPrefixClassName") + "ServiceImpl.java"));
            template.process(dataModel, out);

            System.out.println("ServiceImpl文件生成成功！");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


}


class Function1 implements Runnable {
    private String parameter1;

    private List parameter2;

    public Function1(String parameter1, List parameter2) {
        this.parameter1 = parameter1;
        this.parameter2 = parameter2;
    }

    @Override
    public void run() {
        // 在这里使用参数
        System.out.println(Thread.currentThread().getName() + ": Function1 start");
        CodeGenerator.generateEntityClass(parameter1, parameter2);
        CodeGenerator.generateEntityXml(parameter1, parameter2);
        System.out.println(Thread.currentThread().getName() + ": Function1 finish");
    }
}


class Function2 implements Runnable {
    private String parameter1;

    private List parameter2;

    public Function2(String parameter1, List parameter2) {
        this.parameter1 = parameter1;
        this.parameter2 = parameter2;
    }

    @Override
    public void run() {
        // 在这里使用参数
        System.out.println(Thread.currentThread().getName() + ": Function2 start");
        CodeGenerator.generateMapper(parameter1, parameter2);
        CodeGenerator.generateService(parameter1, parameter2);
        CodeGenerator.generateServiceImpl(parameter1, parameter2);
        System.out.println(Thread.currentThread().getName() + ": Function2 end");
    }
}
